/*
Copyright 2008, 2009 Joonas Lehtolahti

This file is part of Openfire-C.

Openfire-C is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Openfire-C is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Openfire-C.  If not, see <http://www.gnu.org/licenses/>.
*/

int XfireAnalyze_hMyClans(XFINST inst, struct XfirePacket *packet) {
	/* List of clans
	 * http://xfireplus.com/xfwiki/index.php/Packet_9e_00
	 *
	 * USES SINGLE-LIST CALLBACK WAY!
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*
	#define _XFABP clan_list
	
	LinkedList *clanid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	LinkedList *longname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x02));
	LinkedList *shortname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x72));
	LinkedList *clantype_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x34));
	
	LinkedList *clan_list = LLcreate();
	
	if (clanid_list && longname_list && shortname_list && clantype_list) {
		if (clanid_list->nodes == longname_list->nodes &&
			longname_list->nodes == shortname_list->nodes &&
			shortname_list->nodes == clantype_list->nodes) {
			
			ListNode *clanid_node = clanid_list->first;
			ListNode *longname_node = longname_list->first;
			ListNode *shortname_node = shortname_list->first;
			ListNode *clantype_node = clantype_list->first;
			
			struct XfClan *xfc;
			
			while (clanid_node) {
				xfc = XfireInst_FindClanByClanid(inst, *(unsigned int*)clanid_node->x);
				if (!xfc) {
					xfc = XfireInst_AddNewClan(inst, *(unsigned int*)clanid_node->x);
				}
				xfc->longname = n0scopy((non0string*)longname_node->x);
				xfc->shortname = n0scopy((non0string*)shortname_node->x);
				xfc->clantype = *(unsigned int*)clantype_node->x;
				
				LLaddLast(clan_list, xfc);
				
				NEXT_NODE(clanid_node);
				NEXT_NODE(longname_node);
				NEXT_NODE(shortname_node);
				NEXT_NODE(clantype_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			/* internal handling */
			if (retval & XFIH_HANDLED) {
				ListNode *clan_node = clan_list->first;
				while (clan_node) {
					xfc = (struct XfClan*)clan_node->x;
					LLaddLast(inst->self->extdata->clans, xfc);
					
					NEXT_NODE(clan_node);
				}
			}
		}
		else {
			/* Different list lengths */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(clan_list, NULL);
	LLdelete(clantype_list, NULL);
	LLdelete(shortname_list, NULL);
	LLdelete(longname_list, NULL);
	LLdelete(clanid_list, NULL);
	
	return retval;
}

int XfireAnalyze_hClanMembers(XFINST inst, struct XfirePacket *packet) {
	/* List of clan members
	 * http://xfireplus.com/xfwiki/index.php/Packet_9f_00
	 * 
	 * Uses single-list callback way
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT struct XfClan *, LinkedList*
	#define _XFABP xfc, member_list
	
	unsigned int *clanid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	LinkedList *userid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x01));
	LinkedList *username_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x02));
	LinkedList *nickname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x0d));
	/* TODO: Add the rest of the attributes when known */
	LinkedList *member_list = LLcreate();
	
	if (clanid_value && userid_list && username_list && nickname_list) {
		if (userid_list->nodes == username_list->nodes &&
			username_list->nodes == nickname_list->nodes) {
			
			
			struct XfClan *xfc = XfireInst_FindClanByClanid(inst, *(unsigned int*)clanid_value);
			
			if (xfc) {
				ListNode *userid_node = userid_list->first;
				ListNode *username_node = username_list->first;
				ListNode *nickname_node = nickname_list->first;
				
				struct XfFriend *xfu;
				struct XfClanMember xfcm_test, *xfcm;
				TreeNode *xfcm_node;
				
				while (userid_node) {
					unsigned int userid = *(unsigned int*)userid_node->x;
					xfu = XfireInst_FindUserByUserid(inst, userid);
					if (!xfu) {
						/* Unknown user, create new and add to "other people" */
						xfu = XfireFriend();
						xfu->userid = userid;
						BTreeAdd(inst->other_people, xfu);
					}
					n0sfree(xfu->username);
					xfu->username = n0scopy((non0string*)username_node->x);
					if (!xfu->nickname) {
						xfu->nickname = n0scopy((non0string*)nickname_node->x);
					}
					
					xfcm_test.user = xfu;
					xfcm_node = BTreeFind(xfc->members, &xfcm_test);
					if (xfcm_node) {
						xfcm = (struct XfClanMember *)xfcm_node->x;
						BTreeDel(xfc->members, xfcm_node);
						n0sfree(xfcm->nickname);
						xfcm->nickname = n0scopy((non0string*)nickname_node->x);
					}
					else {
						xfcm = XfireClanMember(xfu, n0scopy((non0string*)nickname_node->x), xfc);
					}
					
					LLaddLast(member_list, xfcm);
					
					NEXT_NODE(userid_node);
					NEXT_NODE(username_node);
					NEXT_NODE(nickname_node);
				}
				
				/* include external handlers calling */
				#include "XfirePacketAnalyzeExt.inc"
				/* internal handling */
				if (retval & XFIH_HANDLED) {
					ListNode *member_node = member_list->first;
					while (member_node) {
						BTreeAdd(xfc->members, member_node->x);
						
						NEXT_NODE(member_node);
					}
				}
			}
			else {
				/* Member list for a clan we are in but we don't know about? */
				retval |= XFIH_NONFATAL;
			}
		}
		else {
			/* Different list lengths */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(userid_list, NULL);
	LLdelete(username_list, NULL);
	LLdelete(nickname_list, NULL);
	LLdelete(member_list, NULL);
	
	return retval;
}

int XfireAnalyze_hLeftClan(XFINST inst, struct XfirePacket *packet) {
	/* A member left a clan
	 * http://xfireplus.com/xfwiki/index.php/Packet_a0_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT struct XfFriend*, struct XfClan*
	#define _XFABP xff, xfc
	
	unsigned int *userid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x01));
	unsigned int *clanid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	
	if (userid_value && clanid_value) {
		struct XfFriend *xff = XfireInst_FindUserByUserid(inst, *userid_value);
		struct XfClan *xfc = XfireInst_FindClanByClanid(inst, *clanid_value);
		
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* internal handling */
		if (retval & XFIH_HANDLED) {
			if (xff && xfc) {
				/* Remove the clan reference from the user instance */
				LinkedList *userclans = xff->extdata->clans;
				ListNode *clannode = userclans->first;
				struct XfClanMember clanmember, *oldm;
				TreeNode *membernode;
				
				while (clannode) {
					if ((struct XfClan*)clannode->x == xfc) {
						/* found the clan */
						LLdelNode(clannode);
						break;
					}
					NEXT_NODE(clannode);
				}
				if (!clannode) {
					/* clan was not found ??? */
					retval |= XFIH_NONFATAL;
				}
				
				/* Remove the member info from the clan */
				clanmember.user = xff;
				membernode = BTreeFind(xfc->members, &clanmember);
				if (membernode) {
					oldm = (struct XfClanMember *)membernode->x;
					BTreeDel(xfc->members, membernode);
					FreeXfireClanMember(oldm);
				}
				else {
					/* Member not found from the clan ??? */
					retval |= XFIH_NONFATAL;
				}
			}
			else {
				/* For some reason the user or clan was not found,
				 * mark possible error in library */
				retval |= XFIH_NONFATAL;
			}
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	
	return retval;
}

int XfireAnalyze_hClanNews(XFINST inst, struct XfirePacket *packet) {
	/* List of news items for clans
	 * http://xfireplus.com/xfwiki/index.php/Packet_b1_00
	 *
	 * USES SINGLE-LIST CALLBACK WAY!
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*
	#define _XFABP news_list
	
	LinkedList *clanid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	LinkedList *newsid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x91));
	LinkedList *subject_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x54));
	LinkedList *timestamp_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x50));
	LinkedList *username_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x02));
	LinkedList *nickname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x0d));
	LinkedList *extra_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x6d));
	
	LinkedList *news_list = LLcreate();
	
	if (clanid_list && newsid_list && subject_list && timestamp_list &&
		username_list && nickname_list && extra_list && news_list) {
		if (clanid_list->nodes == newsid_list->nodes && newsid_list->nodes == subject_list->nodes &&
			subject_list->nodes == timestamp_list->nodes && timestamp_list->nodes == username_list->nodes &&
			username_list->nodes == nickname_list->nodes && nickname_list->nodes == extra_list->nodes) {
			
			ListNode *clanid_node = clanid_list->first;
			ListNode *newsid_node = newsid_list->first;
			ListNode *subject_node = subject_list->first;
			ListNode *timestamp_node = timestamp_list->first;
			ListNode *username_node = username_list->first;
			ListNode *nickname_node = nickname_list->first;
			ListNode *extra_node = extra_list->first;
			
			struct XfClan *xfc;
			struct XfClanNews *xfcn;
			
			while (clanid_node) {
				xfc = XfireInst_FindClanByClanid(inst, *(unsigned int*)clanid_node->x);
				if (!xfc) {
					/* Unknown clan? */
					retval |= XFIH_NONFATAL;
					continue;
				}
				xfcn = XfireClanNews(*(unsigned int*)newsid_node->x);
				xfcn->clan = xfc;
				xfcn->title = n0scopy((non0string*)subject_node->x);
				xfcn->timestamp = *(unsigned int*)timestamp_node->x;
				xfcn->username = n0scopy((non0string*)username_node->x);
				xfcn->nickname = n0scopy((non0string*)nickname_node->x);
				xfcn->extra = n0scopy((non0string*)extra_node->x);
				
				LLaddLast(news_list, xfcn);
				
				NEXT_NODE(clanid_node);
				NEXT_NODE(newsid_node);
				NEXT_NODE(subject_node);
				NEXT_NODE(timestamp_node);
				NEXT_NODE(username_node);
				NEXT_NODE(nickname_node);
				NEXT_NODE(extra_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			/* internal handling */
			if (retval & XFIH_HANDLED) {
				ListNode *news_node = news_list->first;
				while (news_node) {
					xfcn = (struct XfClanNews*)news_node->x;
					LLaddLast(xfcn->clan->news, xfcn);
					
					NEXT_NODE(news_node);
				}
			}
		}
		else {
			/* Different list lengths */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(clanid_list, NULL);
	LLdelete(newsid_list, NULL);
	LLdelete(subject_list, NULL);
	LLdelete(timestamp_list, NULL);
	LLdelete(username_list, NULL);
	LLdelete(nickname_list, NULL);
	LLdelete(extra_list, NULL);
	
	LLdelete(news_list, NULL);
	
	return retval;
}

int XfireAnalyze_hClanNickChange(XFINST inst, struct XfirePacket *packet) {
	/* A member changed their clan-specific nickname
	 * http://xfireplus.com/xfwiki/index.php/Packet_a2_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT struct XfFriend*, struct XfClan*, non0string*
	#define _XFABP xff, xfc, nick_value
	
	unsigned int *userid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x01));
	unsigned int *clanid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	non0string *nick_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\x0d));
	
	if (userid_value && clanid_value && nick_value) {
		struct XfFriend *xff = XfireInst_FindUserByUserid(inst, *userid_value);
		struct XfClan *xfc = XfireInst_FindClanByClanid(inst, *clanid_value);
		
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* internal handling */
		if (retval & XFIH_HANDLED) {
			if (xff && xfc) {
				TreeNode *membernode;
				struct XfClanMember clanmember, *oldm;				
				clanmember.user = xff;
				membernode = BTreeFind(xfc->members, &clanmember);
				if (membernode) {
					oldm = (struct XfClanMember *)membernode->x;
					n0sfree(oldm->nickname);
					oldm->nickname = n0scopy(nick_value);
				}
				else {
					/* Member not found from the clan ??? */
					retval |= XFIH_NONFATAL;
				}
			}
			else {
				/* For some reason the user or clan was not found,
				 * mark possible error in library */
				retval |= XFIH_NONFATAL;
			}
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	
	return retval;
}

int XfireAnalyze_hClanGroupOrder(XFINST inst, struct XfirePacket *packet) {
	/* TODO http://xfireplus.com/xfwiki/index.php/Packet_a3_00 */
	unsigned int retval = XFIH_HANDLED|XFIH_UNKNOWN;
	
	/* define external handler function type and calling parameters */
	#define _XFABT struct XfirePacket *
	#define _XFABP packet
	/* include external handlers calling */
	#include "XfirePacketAnalyzeExt.inc"
	
	/* No internal handling */
	return retval;
}

int XfireAnalyze_hClanInvite(XFINST inst, struct XfirePacket *packet) {
	/* List of pending clan invitations
	 * http://xfireplus.com/xfwiki/index.php/Packet_a5_00
	 *
	 * USES SINGLE-LIST CALLBACK WAY!
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*
	#define _XFABP invite_list
	
	LinkedList *clanid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	LinkedList *shortname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x72));
	LinkedList *longname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x81));
	LinkedList *type_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x34));
	LinkedList *username_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x02));
	LinkedList *nickname_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x0d));
	LinkedList *text_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x2e));
	
	LinkedList *invite_list = LLcreate();
	
	if (clanid_list && shortname_list && longname_list && type_list &&
		username_list && nickname_list && text_list && invite_list) {
		if (clanid_list->nodes == shortname_list->nodes && shortname_list->nodes == longname_list->nodes &&
			longname_list->nodes == type_list->nodes && type_list->nodes == username_list->nodes &&
			username_list->nodes == nickname_list->nodes && nickname_list->nodes == text_list->nodes) {
			
			ListNode *clanid_node = clanid_list->first;
			ListNode *shortname_node = shortname_list->first;
			ListNode *longname_node = longname_list->first;
			ListNode *type_node = type_list->first;
			ListNode *username_node = username_list->first;
			ListNode *nickname_node = nickname_list->first;
			ListNode *text_node = text_list->first;
			
			while (clanid_node) {
				struct_alloc(invite, XfClanInvite);
				invite->clanid = *(unsigned int*)clanid_node->x;
				invite->shortname = (non0string*)shortname_node->x;
				invite->longname = (non0string*)longname_node->x;
				invite->clantype = *(unsigned int*)type_node->x;
				invite->username = (non0string*)username_node->x;
				invite->nickname = (non0string*)nickname_node->x;
				invite->invite_text = (non0string*)text_node->x;
				
				LLaddLast(invite_list, invite);
				
				NEXT_NODE(clanid_node);
				NEXT_NODE(shortname_node);
				NEXT_NODE(longname_node);
				NEXT_NODE(type_node);
				NEXT_NODE(username_node);
				NEXT_NODE(nickname_node);
				NEXT_NODE(text_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			/* no internal handling */
		}
		else {
			/* Different list lengths */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(clanid_list, NULL);
	LLdelete(shortname_list, NULL);
	LLdelete(longname_list, NULL);
	LLdelete(type_list, NULL);
	LLdelete(username_list, NULL);
	LLdelete(nickname_list, NULL);
	LLdelete(text_list, NULL);
	
	/* Delete invite list */
	LLdelete(invite_list, (FREEFUNC*)free);
	
	return retval;
}

int XfireAnalyze_hClanEvents(XFINST inst, struct XfirePacket *packet) {
	/* List of clan events
	 * http://xfireplus.com/xfwiki/index.php/Packet_aa_00
	 *
	 * USES SINGLE-LIST CALLBACK WAY!
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*
	#define _XFABP event_list
	
	LinkedList *clanid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x6c));
	LinkedList *eventid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x8b));
	LinkedList *gameid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x21));
	LinkedList *title_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x05));
	LinkedList *starttime_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x50));
	LinkedList *endtime_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x8c));
	
	LinkedList *event_list = LLcreate();
	
	if (clanid_list && eventid_list && gameid_list && title_list &&
		starttime_list && endtime_list && event_list) {
		if (clanid_list->nodes == eventid_list->nodes && eventid_list->nodes == gameid_list->nodes &&
			gameid_list->nodes == title_list->nodes && title_list->nodes == starttime_list->nodes &&
			starttime_list->nodes == endtime_list->nodes) {
			
			ListNode *clanid_node = clanid_list->first;
			ListNode *eventid_node = eventid_list->first;
			ListNode *gameid_node = gameid_list->first;
			ListNode *title_node = title_list->first;
			ListNode *starttime_node = starttime_list->first;
			ListNode *endtime_node = endtime_list->first;
			
			struct XfClanEvent *xfce, *xfce_old;
			struct XfClan *xfc;
			
			while (clanid_node) {
				xfc = XfireInst_FindClanByClanid(inst, *(unsigned int*)clanid_node->x);
				xfce = XfireClanEvent(*(unsigned int*)eventid_node->x);
				xfce->clan = xfc;
				xfce->gameid = *(unsigned int*)gameid_node->x;
				xfce->title = n0scopy((non0string*)title_node->x);
				xfce->starttime = *(unsigned int*)starttime_node->x;
				xfce->endtime = *(unsigned int*)endtime_node->x;
				
				LLaddLast(event_list, xfce);
				
				NEXT_NODE(clanid_node);
				NEXT_NODE(eventid_node);
				NEXT_NODE(gameid_node);
				NEXT_NODE(title_node);
				NEXT_NODE(starttime_node);
				NEXT_NODE(endtime_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			/* internal handling */
			if (retval & XFIH_HANDLED) {
				ListNode *event_node = event_list->first;
				
				while (event_node) {
					xfce = (struct XfClanEvent *)event_node->x;
					xfc = xfce->clan;
					xfce_old = XfireInst_FindClanEventByEventid(inst, xfc, xfce->eventid);
					if (xfce_old) {
						/* Event already exists, modify old */
						xfce_old->gameid = xfce->gameid;
						n0sfree(xfce_old->title);
						xfce_old->title = n0scopy(xfce->title);
						xfce_old->starttime = xfce->starttime;
						xfce_old->endtime = xfce->endtime;
						/* Copied information to the old event, delete new */
						FreeXfireClanEvent(xfce);
					}
					else {
						/* Add the event */
						LLaddLast(xfc->events, xfce);
					}
					
					NEXT_NODE(event_node);
				}
				LLdelete(event_list, NULL);
			}
			else {
				/* Free the new events :( */
				LLdelete(event_list, (FREEFUNC*)FreeXfireClanEvent);
			}
		}
		else {
			/* Different list lengths */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(clanid_list, NULL);
	LLdelete(eventid_list, NULL);
	LLdelete(gameid_list, NULL);
	LLdelete(title_list, NULL);
	LLdelete(starttime_list, NULL);
	LLdelete(endtime_list, NULL);
	
	return retval;
}

int XfireAnalyze_hClanEventDeleted(XFINST inst, struct XfirePacket *packet) {
	/* An event was deleted from some clan
	 * http://xfireplus.com/xfwiki/index.php/Packet_ab_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT struct XfClanEvent*
	#define _XFABP event
	
	unsigned int *eventid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x8b));
	
	if (eventid_value) {
		ListNode *clan_node = inst->self->extdata->clans->first;
		struct XfClan *xfc;
		struct XfClanEvent *event = NULL;
		
		while (clan_node) {
			xfc = (struct XfClan*)clan_node->x;
			event = XfireInst_FindClanEventByEventid(inst, xfc, *eventid_value);
			if (event) break;
			NEXT_NODE(clan_node);
		}
		
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* internal handling */
		if (retval & XFIH_HANDLED) {
			if (event) {
				LLdelNode(clan_node);
				FreeXfireClanEvent(event);
			}
			else {
				/* Delete an event we didn't know about? */
				/* NOTE: This can actually happen because of a bug in Xfire
				 * servers not sending list of events after joining a clan,
				 * but only when logging in. */
				retval |= XFIH_NONFATAL;
			}
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	
	return retval;
}

